<?php

namespace App\Service\Cruise\Check;

use App\Jobs\Cruise\AgainstExpire;
use App\Library\Rms\RmsShopApi;
use App\Models\Cruise\CruiseCheckAgainstModel;
use App\Models\Cruise\CruiseCheckRectifyModel;
use App\Models\Cruise\CruiseOrderModel;
use App\Models\Cruise\CruiseOrderProcessModel;
use App\Models\OpenShop\Common\OpenShopOrderManagerModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopMainProcessModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopOrganizationManageUserModel;
use App\Models\System\SystemNotifyCenterModel;
use App\Service\BaseService;
use App\Service\Common\SendVoiceService;
use App\Service\OpenShop\Feishu\ShopCheckAcceptService;
use App\Service\Rms\ShopService;
use App\Service\System\SystemNotifyService;
use Carbon\Carbon;
use GuzzleHttp\Exception\GuzzleException;
use App\Enums\BaseErrorCode;
use App\Enums\OpenShop\InvestmentPromotion\OrganizationManageEnum;
use App\Exceptions\Custom\ResponseHttpException;
use App\Models\Common\OperateLogModel;
use App\Models\Cruise\CruiseCheckAgainstShopMappingModel;
use App\Models\OpenShop\InvestmentPromotion\OpenShopUserBaseInfoModel;
use App\Remote\Rms\RmsUserRemote;
use App\Scope\Shop\ShopScope;
use App\Service\OpenShop\Feishu\OrganizationManageService;
use App\Service\OpenShop\User\RmsUserService;
use Exception;

class CruiseCheckAgainstService extends BaseService
{
    const END_TIME_DAY                       = 10;//违约函过期时间-10个自然日
    const END_TIME_DAY_CASH_OFF              = 8; //违约函到期8天后停收银-8个自然日
    const CREATE_CRUISE_CHECK_AGAINST        = 1; //违约函生成提醒
    const WARN_CRUISE_CHECK_AGAINST          = 2; //违约函临期提醒(警告)
    const PUNISH_CRUISE_CHECK_AGAINST        = 3; //违约函临期提醒（处罚）
    const PUNISH_CRUISE_CHECK_AGAINST_EXPIRE = 4; //违约函已过期提醒(处罚)
    const PUNISH_CRUISE_CHECK_RECTIFY        = 5; //整改单生成提醒
    const PUNISH_CRUISE_CHECK_RECTIFY_EXPIRE = 6; //整改单到期提醒

    /**
     * 添加违约函
     * @return void
     * @throws GuzzleException
     */
    public static function addAgainst($id, $level, $type, $price, $behaviorDesc, $rectifyPlan)
    {
        $cruiseOrder = CruiseOrderModel::query()
            ->where('id', $id)
            ->with(['checkTaskDetailRel'])
            ->first();

        if (null == $cruiseOrder) {
            self::throwErr('获取订单失败');
        }

        /*CruiseCheckAgainstModel::add(
            $cruiseOrder->shopId,
            (int)optional($cruiseOrder->checkTaskDetailRel)->id,
            CruiseCheckAgainstModel::BUSINESS_TYPE_RECTIFY,
            (int)optional($cruiseOrder->checkTaskDetailRel)->id,
            self::getSerialNumByLevel($level),
            self::getAgainstVersionByShopId($cruiseOrder->shopId),
            $price,
            time() + 7 * 86400,
            $level,
            $type,
            $behaviorDesc,
            $rectifyPlan
        );*/
        $createdAt = CruiseOrderProcessModel::query()
            ->where('cruiseOrderId', $id)
            ->where('step', CruiseOrderProcessModel::PROCESS_SUBMITTED)
            ->orderByDesc('id')
            ->value('createdAt');//流程任务提交日期
        //统一生成违约函
        self::addCheckAgainst(
            $cruiseOrder->shopId, $price, $level, $type, (int)optional($cruiseOrder->checkTaskDetailRel)->id,
            CruiseCheckAgainstModel::BUSINESS_TYPE_RECTIFY, (int)optional($cruiseOrder->checkTaskDetailRel)->id, $behaviorDesc, $rectifyPlan
            , CruiseCheckAgainstModel::TEMPLATE_TYPE_DEFAULT, strtotime($createdAt)
        );


    }


    /**
     * 通过门店ID获得违约函版本号
     * @param int $shopId
     * @return string
     * @throws GuzzleException
     */
    public static function getAgainstVersionByShopId(int $shopId): string
    {
        //通过shopId获得shopCode
        $version = CruiseCheckAgainstShopMappingModel::getVersionByShopId($shopId);
        if ($version) {
            return $version;
        }
        $shopCode = (new RmsShopApi())->getShopByIds([$shopId], ['shopCode'])['data']['shopList'][0]['shopCode'] ?? 0;
        return CruiseCheckAgainstShopMappingsService::getAgainstVersionByShopCode($shopCode);
    }


    /**
     * 通过level获得违约编号
     * @param int $level
     * @return string
     */
    public static function getSerialNumByLevel(int $level): string
    {
        switch ($level) {
            case CruiseCheckAgainstModel::LEVEL_WARNING:
                return 'wyj' . Carbon::now()->format('YmdHis') . substr(microtime(), 2, 6);
            case CruiseCheckAgainstModel::LEVEL_PUNISH:
                return 'wyc' . Carbon::now()->format('YmdHis') . substr(microtime(), 2, 6);
            default:
                return 'wy' . Carbon::now()->format('YmdHis') . substr(microtime(), 2, 6);
        }
    }

    /**
     * 列表
     * @param string $startTime
     * @param string $endTime
     * @param int $level
     * @param string $name
     * @param int $pageSize
     * @param int $pageNum
     * @param string $status
     * @param string $startPayTime
     * @param string $endPayTime
     * @return array
     * @throws GuzzleException
     */
    public static function lists(
        string $startTime, string $endTime, int $level, string $name, int $pageSize, int $pageNum, string $status, string $startPayTime, string $endPayTime
    ): array
    {
        $paginator = CruiseCheckAgainstModel::query()
            ->with(['userIdentityCardRel'])
            ->when(
                $startTime, function ($query) use ($startTime) {
                $query->where('createdAt', '>=', strtotime($startTime));
            }
            )
            ->when(
                $endTime, function ($query) use ($endTime) {
                $query->where('createdAt', '<', strtotime($endTime) + 86400);
            }
            )
            ->when(
                $level > 0, function ($query) use ($level) {
                $query->where('level', $level);
            }
            )
            ->when(
                ShopScope::getShopIdsArr(), function ($query) {
                $query->whereIn("shopId", ShopScope::getShopIdsArr());
            }
            )
            ->when(
                $name, function ($query) use ($name) {//加盟商姓名
                $query->whereRaw(
                    "shopId in (
                    select shopId from open_shop_main_process a
                    left join open_shop_user_identity_card b on a.orderNo=b.orderNo
                    where b.`name` like '%$name%'
                )"
                );
            }
            )
            ->when(
                $status != "", function ($query) use ($status) {
                $query->where('status', (int)$status);
            }
            )
            ->when(
                $startPayTime && $endPayTime, function ($query) use ($startPayTime, $endPayTime) {
                $query->whereBetween('payTime', [strtotime($startPayTime), strtotime($endPayTime) + 86400]);
            }
            )
            ->orderByDesc('payTime')
            ->orderByDesc('id')
            ->paginate($pageSize, ['*'], 'pageNum', $pageNum);
        $shopIds   = collect($paginator->items())->pluck('shopId')->toArray();
        //门店信息
        $shopInfo      = (new RmsShopApi())->getShopByIds($shopIds, ['id', 'shopCode', 'name'])['data']['shopList'] ?? [];
        $shopList      = array_column($shopInfo, null, 'id');
        $createUserIds = collect($paginator->items())->pluck('createdByUid')->toArray();
        $userInfos     = collect(RmsUserService::getRmsUserInfoByUserIds($createUserIds)['data'])->keyBy('id');
        $lists         = $paginator->map(
            function (CruiseCheckAgainstModel $cruiseCheckAgainstModel) use ($userInfos, $shopList) {
                return [
                    'id'           => $cruiseCheckAgainstModel->id,
                    'serialNum'    => $cruiseCheckAgainstModel->serialNum,
                    'shopId'       => $cruiseCheckAgainstModel->shopId,
                    'shopCode'     => $shopList[$cruiseCheckAgainstModel->shopId]['shopCode'] ?? '-',
                    'shopName'     => $shopList[$cruiseCheckAgainstModel->shopId]['name'] ?? '-',
                    'merchantName' => $cruiseCheckAgainstModel->userIdentityCardRel->count() ? $cruiseCheckAgainstModel->userIdentityCardRel[0]->name : '-',
                    'createdAt'    => $cruiseCheckAgainstModel->createdAt->toDateTimeString(),
                    'manageName'   => $userInfos[$cruiseCheckAgainstModel->createdByUid]['username'] ?? '系统',
                    'status'       => $cruiseCheckAgainstModel->status,
                    'level'        => $cruiseCheckAgainstModel->level,
                    'endTime'      => formatDate($cruiseCheckAgainstModel->endTime),
                    'price'        => bcdiv100($cruiseCheckAgainstModel->price),
                    'payTime'      => formatDate($cruiseCheckAgainstModel->payTime),
                ];
            }
        );

        return [
            'pageNum'   => $paginator->currentPage(),
            'pageSize'  => $paginator->perPage(),
            'pageCount' => ceil($paginator->total() / $paginator->perPage()),
            'count'     => $paginator->total(),
            'lists'     => $lists,
        ];
    }


    /**
     * 详情
     * @param int $id
     * @param int $flagNotLog 0-详情 1-预览
     * @param int $flagReplace 默认0-后台获取 1-app获取
     * @return array
     * @throws GuzzleException
     */
    public static function detail(int $id, int $flagNotLog = 0, int $flagReplace = 0): array
    {
        $info = CruiseCheckAgainstModel::query()->with(['userIdentityCardRel', 'signOrderRel'])->find($id);
        if (!$info) {
            throw new ResponseHttpException(BaseErrorCode::$ERROR_OCCURRED, null, "不存在的违约函id");
        }
        //门店信息
        $shopInfo     = (object)current((new RmsShopApi())->getShopByIds([$info['shopId']])["data"]["shopList"]);
        try {
            $manager = OrganizationManageService::getOrganizationInfoByType(OrganizationManageEnum::TYPE_BRANCH_OFFICE, $shopInfo->province);
        } catch (Exception $exception) {
            $manager = [];
        }
        $operationUid = $manager["operationUid"] ?? 0;

        $orderNo           = $info->signOrderRel->count() ? $info->signOrderRel[0]->orderNo : "";
        $managerId = 0;
        if ($orderNo) {
            $managerId = OpenShopOrderManagerModel::getManagerUid($info->signOrderRel[0]->mainProcessId, OpenShopOrderManagerModel::MANAGER_TYPE_5);//督导
        }
        $userBaseInfoQuery = OpenShopUserBaseInfoModel::query()
            ->where('orderNo', $orderNo)
            ->first();

        $userIds = array_filter(array_merge([$operationUid, $shopInfo->councilorId, $info['createdByUid'], $managerId, $info['updatedByUid']]));
        $userInfo          = collect($userIds ? RmsUserRemote::getRmsUserByIds($userIds) : [])->pluck(null, "id");
        $logList = $merchantInfo = [];
        if ($flagNotLog == 0) {//非预览时 返回log
            $merchantInfo = [
                "name"   => $info->userIdentityCardRel->count() ? $info->userIdentityCardRel[0]->name : '-',
                "age"    => $info->userIdentityCardRel->count() ? (new Carbon($info->userIdentityCardRel[0]->birthday))->diffInYears() : '-',
                'mobile' => $userBaseInfoQuery->mobile ?? '-',
            ];
            $logList = OperateLogModel::getData(OperateLogModel::BUSINESS_AGAINST_DETAIL, $info->businessId, $info->id)
                ->map(
                    function ($log) {
                        return [
                            'userId'     => $log->userId,
                            'userName'   => $log->userName ? $log->userName : "系统",
                            'logId'      => $log->logId,
                            'logName'    => $log->logName,
                            'logContent' => $log->logContent,
                            'createdAt'  => $log->createdAt->toDateTimeString(),
                        ];
                    }
                );
        }

        if ($flagReplace == 0) {//$flagReplace-默认0-后台获取 1-app获取 app显示换行-'\n' 后台显示换行-'<br>'
            if (isset($info['behaviorDesc']) && $info['behaviorDesc']) {
                $info['behaviorDesc'] = str_replace('\n', '<br>', $info['behaviorDesc']);
            }
            if (isset($info['rectifyPlan']) && $info['rectifyPlan']) {
                $info['rectifyPlan'] = str_replace('\n', '<br>', $info['rectifyPlan']);
            }
        }
        $rectifyEndTime = formatDate($info['endTime']);
        if ($info['templateType'] == CruiseCheckAgainstModel::TEMPLATE_TYPE_TIMEOUT) {//整改单超期生成超时违约函-显示整改截止时间
            $submitEndTime = CruiseCheckRectifyModel::query()->where('cruiseCheckDetailId', $info['cruiseCheckDetailId'])->value('submitEndTime');
            if ($submitEndTime) {
                $rectifyEndTime = formatDate($submitEndTime);
            }
        }

        $behaviorDesc = $info['behaviorDesc'] ?? "";

        if ($flagReplace == 1) {
            if (strpos($behaviorDesc, '风险类型') !== false) {
                $behaviorDesc = ltrim(strip_tags($behaviorDesc), '1.');
                $behaviorDesc = str_replace([';'], "\n", $behaviorDesc);
                $behaviorDesc = str_replace(' ', '', $behaviorDesc);
            }
        }

        return [
            'id'           => $info['id'],
            'serialNum'    => $info['serialNum'],
            'level'        => $info['level'],
            'status'       => $info['status'],
            'type'         => explode(',', $info['type']),
            'price'        => bcdiv100($info['price']),
            'version'      => $info['version'],
            'createdByUid' => $info['createdByUid'],
            'createdAt'    => $info['createdAt']->toDateTimeString(),
            'date'         => formatDateYmd($info['startTime']),
            'manageName'   => $userInfo->get($info['createdByUid'], [])["username"] ?? "系统",
            'endTime'      => formatDate($info['endTime']),
            'behaviorDesc' => $behaviorDesc,
            'rectifyPlan'  => $info['rectifyPlan'],
            'templateType' => $info['templateType'],
            'shopInfo'     => [//门店信息
                'id'                    => $info['shopId'],
                'shopCode'              => $shopInfo->shopCode,
                'shopName'              => $shopInfo->name,
                "addressPrefix"         => $shopInfo->addressPrefix,
                "shopAddress"           => $shopInfo->address,
                "supervisor"            => $userInfo->get($managerId, [])["username"] ?? "",//营运顾问-督导
                "supervisorMobile"      => $userInfo->get($managerId, [])["mobile"] ?? "",
                "provincialTotalMobile" => $userInfo->get($manager["operationUid"] ?? 0)["mobile"] ?? "",
                "provincialTotal"       => $manager["operationName"] ?? "",//省总
            ],
            'merchantInfo'   => $merchantInfo,//商家信息
            'logList'        => $logList,     //订单日志
            'updatedByUid'   => $info['updatedByUid'],
            'updatedAt'      => $info['updatedAt']->toDateTimeString(),
            'updateName'     => $userInfo->get($info['updatedByUid'], [])["username"] ?? "系统",
            'rectifyEndTime' => $rectifyEndTime,
            'reason'         => $info['reason'],
        ];
    }

    /**
     * 新增违约函
     * @param $request
     * @param int $price
     * @throws GuzzleException
     */
    public static function add($request, $price = 0)
    {
        try {
            self::addCheckAgainst(
                $request->shopId, $price, $request->level, $request->type, 0,
                CruiseCheckAgainstModel::BUSINESS_TYPE_WEB, 0, $request->behaviorDesc, $request->rectifyPlan
                , CruiseCheckAgainstModel::TEMPLATE_TYPE_DEFAULT, strtotime($request->startTime)
            );

        } catch (Exception $e) {
            handleException($e);
        }
    }

    /**
     * 处理违约函
     * @param int $id
     * @param $request
     * @throws Exception
     */
    public static function edit(int $id, $request)
    {
        $info = CruiseCheckAgainstModel::query()->find($id);
        if (!$info) {
            throw new ResponseHttpException(BaseErrorCode::$ERROR_OCCURRED, null, "不存在的违约函id");
        }

        if ($info['status'] != CruiseCheckAgainstModel::STATUS_WAIT) {
            throw new ResponseHttpException(BaseErrorCode::$ERROR_OCCURRED, null, "违约函已处理或已关闭");
        }

        if ($info['level'] == $request->level) {
            throw new ResponseHttpException(BaseErrorCode::$ERROR_OCCURRED, null, "违约函级别已存在");
        }

        if ($info['paidPrice'] > 0) {
            throw new ResponseHttpException(BaseErrorCode::$ERROR_OCCURRED, null, "该违约函已有支付，无法变更");
        }

        try {
            $data = [
                'level' => (int)$request->level,
                'price' => (int)$request->price * 100,
            ];
            CruiseCheckAgainstModel::setCheckAgainstInfoById($id, $data);
            $logContent = '违约级别：' . CruiseCheckAgainstModel::LEVEL_TEXT[$info->level] . "=>" . CruiseCheckAgainstModel::LEVEL_TEXT[$request->level];
            // 操作日志
            OperateLogModel::add(
                OperateLogModel::BUSINESS_AGAINST_DETAIL,
                $info->businessId,
                $id,
                '编辑违约函',
                $logContent,
                OperateLogModel::STATUS_WAIT,
                getRmsUserId(),
            );
        } catch (Exception $e) {
            handleException($e);
        }
    }

    /**
     * 撤销违约函
     * @param $request
     * @throws Exception
     */
    public static function cancel($request)
    {
        $info = CruiseCheckAgainstModel::query()->find($request->id);
        if (!$info) {
            throw new ResponseHttpException(BaseErrorCode::$ERROR_OCCURRED, null, "不存在的违约函id");
        }

        if ($info['status'] != CruiseCheckAgainstModel::STATUS_WAIT || $info['status'] == CruiseCheckAgainstModel::STATUS_CLOSE) {
            throw new ResponseHttpException(BaseErrorCode::$ERROR_OCCURRED, null, "已撤销的违约函无法撤销");
        }

        if ($info['paidPrice'] > 0) {
            throw new ResponseHttpException(BaseErrorCode::$ERROR_OCCURRED, null, "该违约函已有支付，无法撤销");
        }

        try {
            $reason = $request->reason ?? "";
            $data   = [
                'status' => CruiseCheckAgainstModel::STATUS_CLOSE,
                'reason' => $reason,
            ];
            CruiseCheckAgainstModel::setCheckAgainstInfoById($request->id, $data);
            // 操作日志
            OperateLogModel::add(
                OperateLogModel::BUSINESS_AGAINST_DETAIL,
                $info->businessId,
                $request->id,
                '撤销违约函',
                $reason,
                OperateLogModel::STATUS_WAIT,
                getRmsUserId(),
            );
        } catch (Exception $e) {
            handleException($e);
        }
    }

    /**
     * 新加违约函
     * @param int $shopId
     * @param int $price
     * @param int $level
     * @param string $type
     * @param int $cruiseCheckDetailId
     * @param int $businessType
     * @param int $businessId
     * @param string $behaviorDesc
     * @param string $rectifyPlan
     * @param int $templateType
     * @param int $startTime
     * @throws GuzzleException
     */
    public static function addCheckAgainst(
        int $shopId,
        int $price,
        int $level,
        string $type,
        int $cruiseCheckDetailId,
        $businessType = CruiseCheckAgainstModel::BUSINESS_TYPE_WEB,
        $businessId = 0,
        $behaviorDesc = '',
        $rectifyPlan = '',
        $templateType = CruiseCheckAgainstModel::TEMPLATE_TYPE_DEFAULT,
        $startTime = 0
    )
    {
        $version   = self::getAgainstVersionByShopId($shopId);
        $expireTime = self::END_TIME_DAY * 86400;//周期-10个自然日

        if (config('app.env') == 'qa' || config('app.env') == 'pre') {
            $endTime = time() + 300;
        } else {
            $endTime    = strtotime(date('Y-m-d 23:59:59')) + $expireTime;
        }

        $newPrice     = $price * 100;
        $serialNum = self::getSerialNumByLevel($level);
        $addData = [
            'shopId'              => $shopId,                               //店铺id
            'cruiseCheckDetailId' => $cruiseCheckDetailId,                  //巡检报告id
            'businessType'        => $businessType,                         //1后台手动添加
            'businessId'          => $businessId,                           //关联业务表id 1后台手动添加 2异常报备 3整改违约
            'serialNum'           => $serialNum,                            //违约函编号
            'version'             => $version,                              //违约函版本
            'price'               => $newPrice,                             //违约金额
            'endTime'             => $endTime,                              //截止处理时间
            'level'               => $level,                                //违约级别 0默认 1警告 2处罚
            'type'                => $type,                                 //违约分类 0-默认 1-自采管理 2-门店QSC\\运营管理
            'behaviorDesc'        => $behaviorDesc,                         //违约行为描述
            'rectifyPlan'         => $rectifyPlan,                          //整改措施
            'templateType'        => $templateType,                         //违约函模板类型 0常规模板 1超时模板
            'startTime'           => $startTime,                            //违约函实际产生时间
        ];

        $res = CruiseCheckAgainstModel::addCheckAgainst($addData);
        //门店信息
        $shopInfo     = (object)current((new RmsShopApi())->getShopByIds([$shopId])["data"]["shopList"]);

        $levelTxt   = CruiseCheckAgainstModel::LEVEL_TEXT[$level];
        $typeTxt = '';
        if ($type) {
            $type = explode(',', $type);
            if (count($type) > 0) {
                foreach ($type as $v) {
                    $typeTxt.= CruiseCheckAgainstModel::TYPE_TEXT[$v]." ";
                }
            }
        }
        $logContent = <<<STR
违约门店: {$shopInfo->name}
违约函级别: {$levelTxt}
违约函分类: {$typeTxt}
违约函版本: {$version}
违约金额: {$price}
STR;
        // 操作日志
        OperateLogModel::add(
            OperateLogModel::BUSINESS_AGAINST_DETAIL,
            $businessId,
            $res->id,
            '开具违约函',
            $logContent,
            OperateLogModel::STATUS_WAIT,
            getRmsUserId(),
        );

        // 如果0-6点，推迟到8点执行，否则立即执行
        if (date('H') >= 0 && date('H') <= 5) {

            // 今天8点
            $delay = strtotime(date('Y-m-d 08:i:s')) - time();

            dispatch(function () use ($shopId, $endTime, $res, $level) {

                // 违约函商家app通知
                self::sendSystemNotify($shopId, $endTime, self::CREATE_CRUISE_CHECK_AGAINST, $res->id, $level);
            })->delay($delay)->onQueue('{check-expire}');
        } else {

            // 违约函商家app通知
            self::sendSystemNotify($shopId, $endTime, self::CREATE_CRUISE_CHECK_AGAINST, $res->id, $level);
        }

        //违约函到期的事件
        dispatch((new AgainstExpire($res->id))->onQueue('{check-expire}'))->delay($endTime - time());//倒计时=截止时间-当前时间

        //生成违约函 通知督导&城市经理 todo
//        self::addCheckAgainstSendNotice($shopId, $shopInfo, $addData);
    }

    /**
     * 查询门店违约函对应版本
     * @param int $shopId
     * @return array
     * @throws GuzzleException
     */
    public static function shopVersion(int $shopId): array
    {
        $version = self::getAgainstVersionByShopId($shopId);
        return ['version' => $version];
    }


    /**
     * 门店违约函版本预览返回数据
     * @param int $shopId
     * @param int $id
     * @param int $flagReplace 默认0-后台获取 1-app获取
     * @param int $checkId
     * @return array
     * @throws GuzzleException
     */
    public static function shopVersionPreview(int $shopId = 0, int $id = 0, int $flagReplace = 0, int $checkId = 0): array
    {
        $data = [
            'date' => date('Y-m-d'), // 违约函创建时间
            'versionClause' => config('cruise.versionClause', []),//违约函条款
            'stampUrl' => config('cruise.stampUrl', ""),//公司盖章图片url
        ];
        if ($checkId) {//从巡检详情中新建违约函展示时间
            $createdAt = CruiseOrderProcessModel::query()
                ->where('cruiseOrderId', $checkId)
                ->where('step', CruiseOrderProcessModel::PROCESS_SUBMITTED)
                ->orderByDesc('id')
                ->value('createdAt');//流程任务提交日期
            if ($createdAt) {
                $data['date'] = $createdAt->toDateString();
            }
        }

        if ($id > 0) {
            $info = self::detail($id, 1, $flagReplace);
            $data = array_merge($data, $info);
        } elseif ($shopId > 0) {
            //门店信息
            $shopInfo     = (object)current((new RmsShopApi())->getShopByIds([$shopId])["data"]["shopList"]);
            $manager      = OrganizationManageService::getOrganizationInfoByType(
                OrganizationManageEnum::TYPE_BRANCH_OFFICE,
                $shopInfo->province
            );
            $operationUid = $manager["operationUid"] ?? 0;
            $userIds      = array_filter(array_merge([$operationUid, $shopInfo->councilorId]));
            $userInfo     = collect($userIds ? RmsUserRemote::getRmsUserByIds($userIds) : [])->pluck(null, "id");

            $data['shopInfo'] = [//门店信息
                'id'                    => $shopId,
                'shopCode'              => $shopInfo->shopCode,
                'shopName'              => $shopInfo->name,
                "addressPrefix"         => $shopInfo->addressPrefix,
                "shopAddress"           => $shopInfo->address,
                "supervisor"            => $userInfo->get($shopInfo->councilorId, [])["username"] ?? "",
                "supervisorMobile"      => $userInfo->get($shopInfo->councilorId, [])["mobile"] ?? "",
                "provincialTotalMobile" => $userInfo->get($manager["operationUid"] ?? 0)["mobile"] ?? "",
                "provincialTotal"       => $manager["operationName"] ?? "",
            ];
        }

        return $data;
    }


    /**
     * 商家消息及阿里云语音通知
     * @param int $shopId
     * @param string $endTime
     * @param int $type 1:违约函生成提醒 2:违约函临期提醒(警告) 3:违约函临期提醒（处罚） 4:违约函已过期提醒(处罚) 5:整改单生成提醒 6:整改单到期提醒
     * @param int $id 违约函/整改项id
     * @param int $level 违约级别 0默认 1警告 2处罚
     * @param int $num 违约信息数量
     * @throws GuzzleException
     */
    public static function sendSystemNotify(int $shopId, string $endTime, int $type, int $id = 0, int $level = 0, int $num = 1)
    {

        //todo y
        if ($shopId == 0) {
            return;
        }

        //门店信息
        $shopInfo = (object)current((new RmsShopApi())->getShopByIds([$shopId])["data"]["shopList"]);
        $userIds = RmsUserRemote::getShopManagerUserByShopId([$shopId], [], true)['lists'];//通过shopId 获得对应店长的 userId
        if ($shopInfo && $userIds) {//有店长权限 && 没有运营中心权限的用户
            $endDate           = formatDate($endTime);
            $summary           = '';
            $title             = '您有' . $num . '条违约信息，请尽快处理！';                        //app消息标题
            $voiceTemplateCode = config('voiceCloud.templateCode.cruiseCheckAgainst');//语音消息模版code
            $pageUrl           = config('webUrl.notify_web_cdn_url') . '#/pages/audit/report/break-contract?againstId=' . $id;
            if ($level == CruiseCheckAgainstModel::LEVEL_PUNISH) {//处罚跳转到支付页面
                $pageUrl = config('open-shop.m') . 'audit/pay-fine?againstId=' . $id;
            }
            switch ($type) {
                case self::CREATE_CRUISE_CHECK_AGAINST://违约函生成提醒
                    $summary = <<<STR
亲爱的夸父伙伴，门店编号：{$shopInfo->shopCode}有{$num}条违约信息，请在{$endDate}之前完成处理，为了更好保障门店的营运工作,请点击查看详情进行处理。感谢您的理解！
STR;
                    break;
                case self::WARN_CRUISE_CHECK_AGAINST://违约函临期提醒(警告)
                    $title             = '您有' . $num . '条违约信息即将到期，请尽快处理！';
                    $voiceTemplateCode = config('voiceCloud.templateCode.cruiseCheckAgainstWarn');//语音消息模版code
                    $summary           = <<<STR
亲爱的夸父伙伴，门店编号：{$shopInfo->shopCode}有{$num}条违约信息，明天即将到期，请在{$endDate}之前完成处理，为了更好保障门店的营运工作,请点击查看详情进行处理。感谢您的理解！
STR;
                    break;
                case self::PUNISH_CRUISE_CHECK_AGAINST://违约函临期提醒（处罚）
                    $title             = '您有' . $num . '条违约信息即将到期，请尽快处理！';
                    $voiceTemplateCode = config('voiceCloud.templateCode.cruiseCheckAgainstPunish');//语音消息模版code -  '！';//语音消息内容
                    $summary           = <<<STR
亲爱的夸父伙伴，门店编号：{$shopInfo->shopCode}有{$num}条违约信息，明天即将到期。请在{$endDate}之前完成处理，感谢您的理解！（PS：如到期后还未完成处理，系统将会暂停订货通道）
STR;
                    break;
                case self::PUNISH_CRUISE_CHECK_AGAINST_EXPIRE://违约函已过期提醒(处罚)
                    $title             = '您有' . $num . '条违约信息已过期，请尽快处理！';
                    $voiceTemplateCode = config('voiceCloud.templateCode.cruiseCheckAgainstPunishExpire');//语音消息模版code
                    $summary           = <<<STR
亲爱的夸父伙伴，门店编号：{$shopInfo->shopCode}有{$num}条违约信息已过期，门店编号：{$shopInfo->shopCode}已暂停订货通道,请点击查看详情进行处理。感谢您的理解！
STR;
                    break;
                case self::PUNISH_CRUISE_CHECK_RECTIFY://整改单生成提醒
                    $title             = '您有' . $num . '项待整改项，请尽快处理！';
                    $voiceTemplateCode = config('voiceCloud.templateCode.cruiseCheckRectify');//语音消息模版code
                    $summary           = <<<STR
亲爱的夸父伙伴，门店编号：{$shopInfo->shopCode}有{$num}项待整改项，请在{$endDate}之前完成整改，为了更好保障门店的营运工作,请点击查看详情完成整改。感谢您的理解！
STR;
                    $pageUrl           = config('webUrl.notify_web_cdn_url') . '#/pages/audit/rectify/list';
                    break;
                case self::PUNISH_CRUISE_CHECK_RECTIFY_EXPIRE://整改单生成提醒
                    $title             = '您有' . $num . '项待整改项，请尽快处理！';
                    $voiceTemplateCode = config('voiceCloud.templateCode.cruiseCheckRectifyExpire');//语音消息模版code
                    $summary           = <<<STR
亲爱的夸父伙伴，门店编号：{$shopInfo->shopCode}有{$num}项待整改项，明天即将到期。请在{$endDate}之前完成整改，感谢您的理解！（PS：如到期后还未完成处理，系统将会自动生成违约函）
STR;
                    $pageUrl           = config('webUrl.notify_web_cdn_url') . '#/pages/audit/rectify/list';
                    break;
            }
            foreach ($userIds as $v) {
                // 向商家发送违约函生成提醒
                $notify = SystemNotifyService::save(
                    false,
                    $title,
                    SystemNotifyCenterModel::NOTIFY_TYPE_3,
                    SystemNotifyCenterModel::NOTIFY_TARGET_1,
                    '',
                    $title,
                    $pageUrl,
                    SystemNotifyCenterModel::METHOD_TYPE_AUTOMATIC,
                    $summary,
                    '',
                    SystemNotifyCenterModel::IS_POPUP_ON,
                    1,
                    $shopId
                );
                SystemNotifyService::recordLog($notify, '创建消息');
                SystemNotifyService::preSend($notify->id, [$v['userId']]);

                //阿里云语音通知
                if ($v['mobile']) {
                    $templateParam = json_encode(['shopName' => ShopService::trimShopName($shopInfo->name), 'num' => $num]);
                    (new SendVoiceService())->sendVoiceCallByTts($v['mobile'], $voiceTemplateCode, $templateParam);
                }
            }
        }
    }


    /**
     * 商家确认违约函
     * @param int $userId
     * @param $id
     * @return void
     */
    public static function confirm(int $userId, $id)
    {
        $info = CruiseCheckAgainstModel::query()->find($id);
        if (!$info) {
            throw new ResponseHttpException(BaseErrorCode::$ERROR_OCCURRED, null, "不存在的违约函id");
        }

        if ($info->status != CruiseCheckAgainstModel::STATUS_WAIT) {
            throw new ResponseHttpException(BaseErrorCode::$ERROR_OCCURRED, null, "违约函状态不正确");
        }

        if ($info->level != CruiseCheckAgainstModel::LEVEL_WARNING) {
            BaseService::throwErr('只有警告函能确认');
        }

        //违约函变为已处理
        CruiseCheckAgainstModel::query()
            ->where('id', $id)
            ->update([
                'updatedByUid' => $userId,
                'status'       => CruiseCheckAgainstModel::STATUS_OK
            ]);

        // 操作日志
        OperateLogModel::add(
            OperateLogModel::BUSINESS_AGAINST_DETAIL,
            $info->businessId,
            $id,
            '商家已处理',
            'APP确认违约函',
            OperateLogModel::STATUS_OK,
            $userId,
        );
    }

    /**
     * 生成违约函 通知督导&城市经理
     * @param int $shopId
     * @param object $shopInfo
     * @param array $againstInfo
     */
    public static function addCheckAgainstSendNotice(int $shopId, object $shopInfo, array $againstInfo)
    {
        $setKfUserIds = [];

        // 督导
        $mainProcessModel = OpenShopMainProcessModel::query()->where('shopId', $shopId)->first();
        if ($mainProcessModel) {
            $managerId      = OpenShopOrderManagerModel::getManagerUid($mainProcessModel->id ?? 0, OpenShopOrderManagerModel::MANAGER_TYPE_5);
            $setKfUserIds[] = $managerId;
        }

        try {
            $manager = OrganizationManageService::getOrganizationInfoByType(OrganizationManageEnum::TYPE_BRANCH_OFFICE, $shopInfo->province);
        } catch (\Exception $exception) {//处理 该省区没有绑定开店组织 不显示
            $manager = [];
        }

        // 城市经理
        if (isset($manager["id"]) && $manager["id"]) {
            $managers = OpenShopOrganizationManageUserModel::getData($manager["id"], OpenShopOrganizationManageUserModel::TYPE_CITY_MANAGER);
            if ($managers) {
                $setKfUserIds = array_merge($setKfUserIds, array_column($managers, 'userId'));
            }
        }
        if (!$setKfUserIds) {
            return;
        }
    }
}
